import { isArray, isBoolean, isEmptyObject, isFunction, isPromise } from "@/utils/is.js";
import { cloneDeep, merge as mergeObj } from "lodash";
import { useTableSelection } from "@/hooks/useTableSelection.js";
import { useRoute } from "vue-router";
import { PlusSearchProps } from "@/utils/configs.js";

/*
options:
  init: 第一次是否请求
  hasPage: 是否有分页， 默认为true
  searchForm: 搜索参数表单（不包括分页参数）
  fieldMap: 各字段对应的名字（{ page: 'pageNum', pageSize: 'pageSize', data: 'rows', total: 'total' }）
  afterRequest: 请求之后对返回的原始数据做处理，返回false不进行 tableData 和 total 的赋值
  beforeRequest: 请求之前的处理，参数为请求参数（包含分页字段），支持返回Promise，返回false不进行请求
 */
export const useTablePage = (requestFn, options = {}) => {
  if (!requestFn || !isFunction(requestFn)) {
    return;
  }

  const {
    init = true, // 默认请求一次
    hasPage = true,  // 是否有分页
    searchForm = ref({}),
    afterRequest = undefined,
    beforeRequest = undefined,
    fieldMap = {page: "pageNum", pageSize: "pageSize", data: "list", total: "total"}
  } = options;

  const route = useRoute();
  const meta = route.meta || {};

  const {
    page: pageField = "pageNum",
    pageSize: pageSizeField = "pageSize",
    data: dataField = "rows",
    total: totalField = "total"
  } = fieldMap;

  const {selection, onSelectionChange} = useTableSelection();

  const tableData = ref([]);
  const pageInfo = ref({
    page: 1,
    pageSize: 10
  });
  const loadingStatus = ref(false);
  const total = ref(0);

  const showSearchForm = ref(true);

  const fullParams = computed(() => {
    return {
      tableData: tableData.value,
      total: total.value,
      pageInfo: pageInfo.value,
      searchForm: searchForm.value,
      showSearchForm: showSearchForm.value
    };
  });

  function setLoading(bool = true) {
    loadingStatus.value = bool;
  }

  const getList = async (isResetPage = false) => {
    if (isResetPage) {
      resetPage(false)
    }

    const page = {
      [pageField]: pageInfo.value.page,
      [pageSizeField]: pageInfo.value.pageSize
    };
    let query = {
      ...page,
      ...searchForm.value
    };

    console.log('query', query)

    if (beforeRequest && isFunction(beforeRequest)) {
      console.log("before request start");
      let beforeRet = beforeRequest(query, cloneDeep(fullParams.value));

      if (isPromise(beforeRet)) {
        beforeRet = await beforeRet;
      }

      // 只有在返回值为false的时候才中断
      if (isBoolean(beforeRet) && !beforeRet) {
        return;
      } else {
        query = beforeRet;
      }
      console.log("before request end");
    }

    try {
      setLoading();
      let { data } = await requestFn(query);
      if (afterRequest && isFunction(afterRequest)) {
        const afterRet = afterRequest(data, cloneDeep(fullParams.value));
        if (isBoolean(afterRet) && !afterRet) {
          return;
        } else {
          data = afterRet;
        }
        console.log("after request end", data);
      }
      console.log('field map --- ', fieldMap)
      if(hasPage){
        tableData.value = data[dataField] || [];
        total.value = data[totalField] || 0;
      }else{
        tableData.value = data;
      }
      console.log(data)
      return Promise.resolve(data);
    } catch (e) {
      console.error(e?.message ?? e);
      return Promise.reject(e?.message ?? e);
    } finally {
      setLoading(false);
    }
  };

  init && getList();

  function resetForm(data = {}, merge = false) {
    if (!merge) {
      searchForm.value = data;
    } else {
      searchForm.value = mergeObj(searchForm.value, data);
    }
  }
  function resetPage(reload = true) {
    pageInfo.value.page = 1
    reload && getList()
  }

  function reset(
    params = {}
  ) {
    const {form = {}, reload = true, merge = false} = params;

    if (!isEmptyObject(form)) {
      resetForm(form, merge)
    }

    resetPage(reload)
  }

  function onPageChange({page, pageSize}) {
    pageInfo.value.page = page;
    pageInfo.value.pageSize = pageSize;
    getList();
  }

  const generateBinds = (options = {}) => {
    const {
      isSelection = true,
      index = true
    } = options;
    const binds = ref({
      titleBar: {
        title: meta?.title ?? "",
        refresh: true
      },
      showOverflowTooltip: true,
      loadingStatus: loadingStatus.value,
      tableData: tableData.value,
      hasIndexColumn: index,
      isSelection,
      onRefresh: reset,
      pagination: {
        total: total.value,
        modelValue: pageInfo.value
      },
      onPaginationChange: onPageChange
    });
    if (isSelection) {
      Reflect.set(binds.value, "onSelectionChange", onSelectionChange);
    }
    return binds.value;
  };

  const onSearchKeyup = e => {
    if (e instanceof KeyboardEvent) {
      const { key } = e
      if (key.toLowerCase() === 'enter') {
        getList()
      }
    }
  }
  const excludeAbleKeys = ['search', 'reset']
  const excludeAbleMap = {
    [excludeAbleKeys[0]]: 'onSearch',
    [excludeAbleKeys[1]]: 'onReset',
  }
  const generateSearchBinds = (exclude = []) => {
    const binds = ref({
      ...PlusSearchProps,
      prevent: true,
      class: {"plus-search--hide": !showSearchForm.value},
      onSearch: getList,
      onReset: reset,
      searchLoading: loadingStatus,
      modelValue: searchForm.value,
      "onUpdate:modelValue": (value) => (searchForm.value = value),
      "onKeyup": onSearchKeyup
    });

    let _exclude = cloneDeep(exclude)
    if (exclude) {
      if (!isArray(exclude)) {
        _exclude = [_exclude]
      }
    }

    _exclude.map(key => {
      if (excludeAbleKeys.includes(key)) {
        console.log(excludeAbleMap[key])
        delete binds.value[excludeAbleMap[key]]
      }
    })

    console.log(binds.value)

    return binds.value;
  };

  return {
    gGetList: getList,
    gReset: reset,
    gResetForm: resetForm,
    gResetPage: resetPage,
    gOnPageChange: onPageChange,
    gTableData: tableData,
    gTotal: total,
    gLoadingStatus: loadingStatus,
    gPageInfo: pageInfo,
    gShowSearchForm: showSearchForm,
    gRouteMeta: meta,
    gSelection: selection,
    gOnSelectionChange: onSelectionChange,
    getBinds: generateBinds,
    getSearchBinds: generateSearchBinds
  };
};
